import { _decorator, Component, Node, Prefab, Vec3, instantiate, UITransform, size, view, random, randomRange, find } from 'cc';
import { DataManager } from './DataManager';
import { GameManager } from '../GameManager';
import { EventManager, GameEventType } from './EventManager';
import { ObjectPool } from './ObjectPool';

const { ccclass, property } = _decorator;

interface WaveConfig {
    time: number;
    enemyTypes: string[];
    count: number;
    spawnRate: number;
}

@ccclass('EnemySpawner')
export class EnemySpawner extends Component {
    @property([Prefab])
    private enemyPrefabs: Prefab[] = [];
    
    @property([String])
    private enemyTypes: string[] = [];
    
    @property
    private spawnInterval: number = 2;
    
    @property
    private maxEnemies: number = 50;
    
    @property
    private minSpawnDistance: number = 10;
    
    @property
    private maxSpawnDistance: number = 20;
    
    @property
    private useWaves: boolean = false;
    
    @property
    private difficultyScaling: number = 0.1;
    
    private _spawnTimer: number = 0;
    private _enemyCount: number = 0;
    private _waveIndex: number = 0;
    private _currentWave: WaveConfig = null;
    private _waves: WaveConfig[] = [];
    private _difficultyMultiplier: number = 1;
    private _spawnCount: number = 0;
    private _prefabMap: Map<string, Prefab> = new Map();
    
    start() {
        // Map enemy types to prefabs
        for (let i = 0; i < this.enemyTypes.length; i++) {
            if (i < this.enemyPrefabs.length) {
                this._prefabMap.set(this.enemyTypes[i], this.enemyPrefabs[i]);
                
                // Register with object pool
                ObjectPool.instance.registerPrefab(`enemy_${this.enemyTypes[i]}`, this.enemyPrefabs[i], 5);
            }
        }
        
        // Generate waves if using wave-based spawning
        if (this.useWaves) {
            this.generateWaves();
        }
        
        // Listen for game events
        EventManager.instance.on(GameEventType.ENEMY_DEATH, this.onEnemyDeath, this);
        EventManager.instance.on(GameEventType.WAVE_END, this.onWaveEnd, this);
    }
    
    update(deltaTime: number) {
        if (GameManager.instance.isGameOver || !GameManager.instance.isGameStarted) {
            return;
        }
        
        // Update spawn timer
        this._spawnTimer += deltaTime;
        
        // Handle wave-based or continuous spawning
        if (this.useWaves) {
            this.updateWaveSpawning(deltaTime);
        } else {
            this.updateContinuousSpawning(deltaTime);
        }
    }
    
    private updateContinuousSpawning(deltaTime: number): void {
        // Check if it's time to spawn and if we haven't reached max enemies
        if (this._spawnTimer >= this.spawnInterval && this._enemyCount < this.maxEnemies) {
            this.spawnEnemy();
            this._spawnTimer = 0;
            
            // Increase difficulty over time
            this.updateDifficulty();
        }
    }
    
    private updateWaveSpawning(deltaTime: number): void {
        // Check if a wave is active
        if (!this._currentWave) {
            // Start first wave or wait for next wave
            if (this._waveIndex < this._waves.length) {
                this.startWave(this._waveIndex);
            }
            return;
        }
        
        // Check if it's time to spawn and if we haven't reached max enemies
        if (this._spawnTimer >= this._currentWave.spawnRate && this._spawnCount < this._currentWave.count) {
            // Spawn an enemy from the current wave
            this.spawnWaveEnemy();
            this._spawnTimer = 0;
            
            // Check if wave is complete
            if (this._spawnCount >= this._currentWave.count) {
                // Wait for all enemies to be defeated
                if (this._enemyCount <= 0) {
                    this.endWave();
                }
            }
        }
    }
    
    private spawnEnemy(): void {
        // Select a random enemy type based on current level/time
        const enemyType = this.selectEnemyType();
        
        // Get spawn position
        const spawnPos = this.getSpawnPosition();
        
        // Create enemy
        this.createEnemy(enemyType, spawnPos);
    }
    
    private spawnWaveEnemy(): void {
        if (!this._currentWave) return;
        
        // Select a random enemy type from the wave
        const typeIndex = Math.floor(Math.random() * this._currentWave.enemyTypes.length);
        const enemyType = this._currentWave.enemyTypes[typeIndex];
        
        // Get spawn position
        const spawnPos = this.getSpawnPosition();
        
        // Create enemy
        this.createEnemy(enemyType, spawnPos);
        
        // Increment spawn count
        this._spawnCount++;
    }
    
    private createEnemy(enemyType: string, position: Vec3): void {
        // Try to get from object pool first
        const poolKey = `enemy_${enemyType}`;
        let enemyNode = ObjectPool.instance.getObject(poolKey, position);
        
        // If not available in pool, create from prefab
        if (!enemyNode) {
            const prefab = this._prefabMap.get(enemyType);
            if (!prefab) {
                console.error(`Enemy prefab not found for type: ${enemyType}`);
                return;
            }
            
            // Find or create enemies container node
            const enemiesNode = find('Enemies') || new Node('Enemies');
            if (enemiesNode.parent === null) {
                this.node.scene.addChild(enemiesNode);
            }
            
            // Create enemy
            enemyNode = instantiate(prefab);
            enemiesNode.addChild(enemyNode);
            enemyNode.position = position;
            
            // Set enemy type
            const enemyController = enemyNode.getComponent('EnemyController');
            if (enemyController) {
                // This would be the right place to set enemy properties
                // enemyController.enemyId = enemyType;
            }
        }
        
        // Increment enemy count
        this._enemyCount++;
    }
    
    private selectEnemyType(): string {
        // Get current level for difficulty scaling
        const currentLevel = GameManager.instance.getLevel();
        
        // Determine which enemy types are available based on level
        const availableTypes = this.enemyTypes.filter((_, index) => {
            // Simple logic: unlock new enemy types as player levels up
            // More complex logic would come from a difficulty curve defined in DataManager
            return index <= Math.min(currentLevel - 1, this.enemyTypes.length - 1);
        });
        
        // Select random enemy type from available ones
        const typeIndex = Math.floor(Math.random() * availableTypes.length);
        return availableTypes[typeIndex];
    }
    
    private getSpawnPosition(): Vec3 {
        // Get player position
        const player = GameManager.instance.getPlayer();
        if (!player) {
            // If no player, spawn at origin
            return new Vec3(0, 0, 0);
        }
        
        // Get a random position outside the screen but not too far
        const playerPos = player.position;
        const distance = randomRange(this.minSpawnDistance, this.maxSpawnDistance);
        const angle = Math.random() * Math.PI * 2;
        
        const x = playerPos.x + Math.cos(angle) * distance;
        const y = playerPos.y + Math.sin(angle) * distance;
        
        return new Vec3(x, y, 0);
    }
    
    private generateWaves(): void {
        // In a full implementation, this would load wave data from DataManager
        // For now, we'll generate some simple waves
        
        // First wave: basic enemies
        this._waves.push({
            time: 0,
            enemyTypes: [this.enemyTypes[0]],
            count: 10,
            spawnRate: 1.5
        });
        
        // Second wave: more enemies
        if (this.enemyTypes.length > 0) {
            this._waves.push({
                time: 60, // 1 minute after start
                enemyTypes: [this.enemyTypes[0]],
                count: 15,
                spawnRate: 1.2
            });
        }
        
        // Third wave: add second enemy type if available
        if (this.enemyTypes.length > 1) {
            this._waves.push({
                time: 120, // 2 minutes after start
                enemyTypes: [this.enemyTypes[0], this.enemyTypes[1]],
                count: 20,
                spawnRate: 1.0
            });
        }
        
        // Fourth wave: harder
        if (this.enemyTypes.length > 1) {
            this._waves.push({
                time: 180, // 3 minutes after start
                enemyTypes: [this.enemyTypes[0], this.enemyTypes[1]],
                count: 25,
                spawnRate: 0.8
            });
        }
        
        // Later waves: all enemy types
        if (this.enemyTypes.length > 2) {
            this._waves.push({
                time: 240, // 4 minutes after start
                enemyTypes: this.enemyTypes,
                count: 30,
                spawnRate: 0.6
            });
        }
    }
    
    private startWave(waveIndex: number): void {
        if (waveIndex >= this._waves.length) return;
        
        this._currentWave = this._waves[waveIndex];
        this._spawnCount = 0;
        
        // Announce wave start
        EventManager.instance.emit(GameEventType.WAVE_START, {
            waveIndex: waveIndex,
            enemyCount: this._currentWave.count
        });
    }
    
    private endWave(): void {
        // Announce wave end
        EventManager.instance.emit(GameEventType.WAVE_END, {
            waveIndex: this._waveIndex
        });
        
        // Prepare for next wave
        this._waveIndex++;
        this._currentWave = null;
        
        // If all waves complete, could trigger a boss or special event
        if (this._waveIndex >= this._waves.length) {
            // Generate additional waves for endless mode
            this.generateEndlessWaves();
        }
    }
    
    private generateEndlessWaves(): void {
        // Generate more challenging waves for endless mode
        const baseCount = 30;
        const baseSpawnRate = 0.5;
        
        for (let i = 0; i < 5; i++) {
            this._waves.push({
                time: 0, // Immediate
                enemyTypes: this.enemyTypes,
                count: baseCount + (i * 10),
                spawnRate: Math.max(0.2, baseSpawnRate - (i * 0.05))
            });
        }
    }
    
    private updateDifficulty(): void {
        // Increase difficulty over time
        const gameTime = GameManager.instance.getGameTime();
        this._difficultyMultiplier = 1 + (gameTime / 60) * this.difficultyScaling;
        
        // Adjust spawn rate based on difficulty
        const adjustedInterval = this.spawnInterval / this._difficultyMultiplier;
        this.spawnInterval = Math.max(0.5, adjustedInterval);
        
        // Adjust max enemies based on difficulty
        this.maxEnemies = Math.min(100, Math.floor(this.maxEnemies * (1 + this.difficultyScaling)));
    }
    
    private onEnemyDeath(data: any): void {
        // Decrease enemy count
        this._enemyCount = Math.max(0, this._enemyCount - 1);
        
        // Check if wave is complete
        if (this.useWaves && this._currentWave && this._spawnCount >= this._currentWave.count && this._enemyCount <= 0) {
            this.endWave();
        }
    }
    
    private onWaveEnd(data: any): void {
        // Nothing to do here for now
    }
    
    onDestroy() {
        // Unregister event listeners
        EventManager.instance.off(GameEventType.ENEMY_DEATH, this.onEnemyDeath, this);
        EventManager.instance.off(GameEventType.WAVE_END, this.onWaveEnd, this);
    }
} 